/**
 * Copyright 2011 Tian Zhu <jrash06@gmail.com>
 * 
 * This file is part of java-object-pool.
 *
 * java-object-pool is free software: you can redistribute it and/or modify
 * it under the terms of the Lesser GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * java-object-pool is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Lesser GNU General Public License for more details.
 *
 * You should have received a copy of the Lesser GNU General Public License
 * along with java-object-pool.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.sf.javaobjectpool;

import java.util.Arrays;

/**
 * A fixed-length array that is allocated and recycled by a set of ObjectPool. <p>
 * 
 * The size is determined during allocation and cannot be changed. Under the
 * hood, several ObjectPools are assigned to maintaining arrays with various
 * length range.
 */
public class PoolableArray<T> {
	/** the default ArrayPool for array with no type info, i.e. Object[] */
	private static ArrayPool<PoolableArray<Object>> pool = new ArrayPool<PoolableArray<Object>>() {
		@Override
		protected PoolableArray<Object> createArray(int len) {
			PoolableArray<Object> o = new PoolableArray<Object>();
			o.storage = new Object[len];
			return o;
		}

		@SuppressWarnings("unchecked")
		@Override
		protected PoolableArray<Object>[] createArrayStorage(int len) {
			return new PoolableArray[len];
		}
		
		@Override
		protected void cleanUp(PoolableArray<Object> o, int len) {
			Arrays.fill(o.storage, len);
		}
	};

	/** physical array to hold the data */
	protected T[] storage;

	/** the logic length of the array */
	protected int len;

	/**
	 * get storage array for fast access NOTE: use it when you know the length
	 * of the array
	 */
	final public T[] getArray() {
		return storage;
	}

	/** return logical len of this array */
	final public int length() {
		return len;
	}

	/** get element at pos i */
	final public T get(int i) {
		if (i < 0 || i >= len)
			throw new ArrayIndexOutOfBoundsException(
					"out of range of logic length");
		return storage[i];
	}

	/** set element at pos i */
	final public void set(int i, T e) {
		if (i < 0 || i >= len)
			throw new ArrayIndexOutOfBoundsException(
					"out of range of logic length");
		storage[i] = e;
	}

	/**
	 * allocate an array with specified logic length, simply proxy it to
	 * ArrayPool
	 */
	public static PoolableArray<Object> allocate(int len) {
		return pool.allocate(len);
	}

	/**
	 * recycle the PoolableArray for type Object array
	 */
	public static void recycle(PoolableArray<Object> o) {
		pool.recycle(o,o.len);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null || !(obj instanceof PoolableArray))
			return false;

		PoolableArray<?> o = (PoolableArray<?>) obj;
		if (this.len != o.len)
			return false;
		if (!Arrays.equals(this.storage, o.storage))
			return false;
		return true;
	}

	@Override
	public int hashCode() {
		return (len * 31) ^ Arrays.hashCode(storage);
	}

}
